//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop


#include "Globals.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
}


//------------------------------------//
//                                    //
//------------------------------------//
void __fastcall TForm1::ExitProgram1Click(TObject *Sender)
{
  Close( );
}


//------------------------------------//
//                                    //
//------------------------------------//
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
  fcloseall( );
  _free( txt.rom );
}


//------------------------------------//
//                                    //
//------------------------------------//
void __fastcall TForm1::OpenROMFile1Click(TObject *Sender)
{
  FILE *rf;
  LONG fsize;

  FOpen1->Title    = "Open ROM File...";
  FOpen1->Filter   = "Snes ROM Files | *.smc; | All Files | *.*";
  FOpen1->Options >> ofAllowMultiSelect;
  //
  if ( FOpen1->Execute( ) )
  { //
    strcpy( rfile, FOpen1->FileName.c_str( ) );
    rf = fopen( rfile, "rb" );
    //
    if ( !rf ){
      ShowMessage("Error: Could not open the ROM file..." );
      return;
    }

    _free( txt.rom );
    txt.rom = (BYTE *)malloc( txt.rmLof = fsize = FileSize( rf ) );
    //
    if ( !txt.rom ){
      fclose( rf );
      ShowMessage( "Fatal Error: Could not allocate needed memory!" );
      Close( );
    }

    // Check for dumb header
    if ( fsize & 0x0200 ){
      fsize -= 0x0200;
      fseek( rf, 0x0200, SEEK_SET );
    }
    // Read in the data
    fread( txt.rom, 1, fsize, rf );
    fclose( rf );
    //---------------------------------//
    // Make sure it's Light Fanstasy 2 //
    //---------------------------------//
    if ( strncmp( &txt.rom[0x1747A], "Light Fantasy 2 95/08/10", 24 ) )
    { //
      ShowMessage("Error: This is not the ROM used.\n"
                  "Please load the correct ROM."
                 );
      _free( txt.rom );
      return;
    }
    //
    ShowMessage( "ROM Loaded successfully!" );
  }
}


//------------------------------------//
//                                    //
//------------------------------------//
void __fastcall TForm1::InsertAScriptBlock1Click(TObject *Sender)
{
  #define LINE_BREAK 0xFE
  #define TEXT_BREAK 0xFF
  #define STRING_END 0x00

  FILE *tf;
  LONG cLine;
  int  pntr,
       Max_ptrs;
  WORD inPosi,
       sLen,
       POINTERS[0x1000];
  //----------------
  BYTE stream[0x1000];
  char buf[256],
       conv[16],
       flag,
       c_test,
       *p1,
       *p2;
  char *codes [ ] =
  {
    "NAME"  , "\xF4",
    "CLRSCR", "\xF5",
    "KEY"   , "\xF6",
    "COLOR" , "\xF7",
    "PAUSE" , "\xF8",
    "CHOICE", "\xFD",
    "\0"    , "\0"
  };

  //
  if ( !txt.rom ){
    ShowMessage("Error: Please load a VALID ROM file first!" );
    return;
  }

  FOpen1->Title   = "Open SCRIPT Text File...";
  FOpen1->Filter  = "Text Files | *.txt";
  FOpen1->Options << ofAllowMultiSelect;

  ListBox1->Clear( );
  cLine          = 0;
  //
  if ( FOpen1->Execute( ) )
  { //
    for  (int i = 0; i < FOpen1->Files->Count; i++ )
    { //
        strcpy( stream, FOpen1->Files->Strings[i].c_str( ) );
        tf = fopen( stream, "rb" );
        //
        if ( !tf ){
          ShowMessage("Error: Could not open the ROM file..." );
          return;
        }

        // Update messages
        ListBox1->Items->Add( "Inserting... " + AnsiString( (char *)stream ) );

        //
        inPosi = strlen( (char *)stream );
        while( stream[ inPosi ] != '\\' && stream[ inPosi ] != '/' )
          inPosi--;
        inPosi++;
        //
        p1 = strchr( (char *)stream, '.' );
        if ( p1 ) p1[0] = 0;

        // Clear Same Text pointer test array
        memset( POINTERS, 0, 0x2000 );

    //    txt.blStart   = Snes2Pc( strtoul( &stream[ inPosi ], NULL, 16 ) );
        txt.blStart   = strtoul( &stream[ inPosi ], NULL, 16 );
        //
        pntr = *(WORD *)&txt.rom[ Snes2Pc(txt.blStart) ];
        Max_ptrs   = (pntr - (txt.blStart & 0xFFFF)) & 0x0FFF;
        Max_ptrs >>= 1;
        pntr       = 0;

        // "POINTERS" should be dynamically allocated
        // Load up all the old pointers
        while( pntr < Max_ptrs )
          POINTERS[ pntr++ ] = *(WORD *)&txt.rom[ Snes2Pc(txt.blStart) + (pntr << 1) ];

        //  Loop til we find the Maximum Insert Point
        txt.blMaximum = 0;
        while( fgets( buf, 256, tf ) && !feof( tf )) {
          //
          cLine++;
          if ( !strncmpi( buf, ".MAXIMUM", 8 ) ){
            sscanf( buf, "%s %X", &stream, &txt.blMaximum );
            break;
          }
        }
        //
        if ( !txt.blMaximum ){
           ShowMessage("Fatal Error: Could not find the Offset for\n"
                       "Maximum insert Point in the Text file."
                      );
           return;
        }
        //
    //    txt.blMaximum = Snes2Pc( txt.blMaximum );

        // Get the starting offsets and stuff
        txt.txOffset = ( txt.blStart & 0xFF0000 );
        txt.txOffset += *(WORD *)&txt.rom[ Snes2Pc( txt.blStart ) ];
        // Assign a Pointer to the Pointer Table
        txt.ptData = (WORD *)&txt.rom[ Snes2Pc(txt.blStart) ];
        //--------------------------//
        //                          //
        //--------------------------//
        while( fgets( buf, 256, tf ) && ++cLine )
        { // Do we have a string to insert?
          if ( !strncmpi( buf, ".STRING", 7 ) )
          { // Get the pointer Index
            sscanf( buf, "%s %d", &buf[128], &txt.txPtrIndex );

            // First make sure THIS pointer is not a duplicate
            for ( int c = 0; c < txt.txPtrIndex; c++ ){
              if ( POINTERS[ txt.txPtrIndex ] == POINTERS[ c ] ){
                txt.ptData[ txt.txPtrIndex ] = txt.ptData[ c ];
                goto Duplicate_String;
              }

    //          if ( txt.ptData[ txt.txPtrIndex ] == POINTERS[ c ] ){
    //            txt.ptData[ txt.txPtrIndex ] = txt.ptData[ c ];
    //            goto Duplicate_String;
    //          }
            }

            // Next String
            fgets( buf, 256, tf );
            RemoveLF_CR( buf );
            // Make sure it's not a commented string
            if ( buf[0] == ';' ){
              cLine++;
              continue;
            }

            // Set the pointer
            txt.ptData[ txt.txPtrIndex ] = (txt.txOffset & 0xFFFF) | 0x8000;

            inPosi = 0;
            cLine++;
            sLen = strlen( buf );
            //----------------------//
            // Loop through strings //
            //----------------------//
            while( !strstr( buf, ".ENDS" ) )
            { // Zero flag so if an empty string read in,
              // no garbage is saved!
              flag = 0;
              // Try to Compress anything!
              sLen = Compress( buf, sLen );

              // Conversion Loop
              for ( int c = 0; c < sLen; c++ )
              { //-------------------------//
                // Check for control codes //
                //-------------------------//
                if ( buf[ c ] == '[' )
                { // Get to the code
                  c++;
                  c_test = 0;
                  flag   = 0;
                  while( codes[ c_test ][ 0 ] )
                  { // Do some comparisons
                    if ( !strncmpi( &buf[c], codes[ c_test ], strlen( codes[ c_test ] )) ) {
                      stream[ inPosi++ ] = codes[ c_test + 1 ][0];
                      // Advance Testing DAta's curent position
                      c += strlen( codes[ c_test ] );
                      // If this is true, do NOT set the flag!
                      if ( buf[ c ] == '$' ) break;
                      // We found what we need! No more test
                      flag = 1;
                      // Decrementc since it's part of a FOR loop
    //                  c--;
                      break;
                    } // END IF
                    //
                    c_test += 2;
                  }

                  // If FLAG still zero, no code match was found!
                  if ( !flag )
                  { // Check for HEX Only codes
                    if ( buf[c] == '$')
                    { //
                      c++;
                      while( buf[c] != ']' ){
                        memcpy( conv, &buf[c], 2 ); conv[ 2 ] = 0;
                        stream[ inPosi++ ] = strtol( conv, NULL, 16 );
                        c += 2;
                      }

                      //
                      stream[ inPosi ] = STRING_END;
                    }
                    else
                    { // If it comes here then it's regular data
                      stream[ inPosi++ ] = buf[ --c ];
                      stream[ inPosi   ] = STRING_END;
                    }
                  } // END IF

                } // END IF - Control Codes
                else
                { // regular text
                  stream[ inPosi++ ] = buf[ c ];
                  stream[ inPosi   ] = STRING_END;
                } // END IF - Everything else
              }

              // Next String
              _NextString:
              fgets( buf, 256, tf );
              RemoveLF_CR( buf );
              // Make sure it's not a commented string
              if ( buf[0] == ';' ){
                cLine++;
                goto _NextString;
              }
              //
              sLen = strlen( buf );
              cLine++;

              // Get the next string
    /*
              fgets( buf, 256, tf );
              RemoveLF_CR( buf );
              sLen = strlen( buf );
              cLine++;
    */
              // Line break
              if ( !strstr( buf, ".ENDS" ) ) stream[ inPosi++ ] = LINE_BREAK;
            } // WEND

            // End of String
            stream[ inPosi++ ] = TEXT_BREAK;
            stream[ inPosi ]   = STRING_END;

            // Try to store the data
            if ( ( inPosi + Snes2Pc( txt.txOffset) ) <= Snes2Pc( txt.blMaximum ) ){
              memcpy( &txt.rom[ Snes2Pc(txt.txOffset) ], stream, inPosi );
              txt.txOffset += inPosi;
            } else {
    //          ShowMessage("Error: Text Block Filled with text remaining..." );
              ListBox1->Items->Add( "Error: Text Block Filled with text remaining..." );
              ListBox1->Items->Add( "------------ Last String Processed ------------" );
              ListBox1->Items->Add( AnsiString( buf ) );
              ListBox1->Items->Add( "At Line: " + IntToStr( cLine ) );
              ListBox1->Items->Add( " " );              
              fclose( tf );
              inPosi = -1;
              break;
  //            return;
            }

          }// END IF - Text Found

          //
          Duplicate_String:
          CheckMSG( );
        } // WEND - Search for Text

        // Save the new pointers
    //    memcpy( &txt.rom[ txt.blStart ], (BYTE *)txt.ptData, (txt.txPtrIndex << 1) );
        if ( (short)inPosi != -1 ) ListBox1->Items->Add( "Text inserted successfully!" );
        ListBox1->Items->Add( ";##################################################" );        
    } // NEXT - Files to Insert

  }// END IF - File Opertaion

  // Close shit
  fcloseall( );
}


//---------------------------//
//                           //
//---------------------------//
void __fastcall TForm1::SaveROMFile1Click(TObject *Sender)
{
  FILE *sf;

  if ( txt.rom ){
    sf = fopen( rfile, "rb+" );
    //
    if ( !sf ){
      ShowMessage("Fatal Error: Could not save the ROM file." );
      fclose( sf );
      return;
    }
    //
    fseek( sf, 0, SEEK_SET );
    fwrite( txt.rom, 1, txt.rmLof, sf );
    fclose( sf );
    //
    ShowMessage( "ROM file was saved!" );
  } else {
    ShowMessage( "You must first load a ROM file!" );
  }
}


//---------------------------//
//                           //
//---------------------------//
void __fastcall TForm1::LoadCompressionTableFile1Click(TObject *Sender)
{
  FILE *tf;
  char buf[256];

  FOpen1->Title  = "Open COMPRESSION Table File...";
  FOpen1->Filter = "Table File | *.tbl";
  //
  if ( FOpen1->Execute( ) )
  { //
    tf = fopen( FOpen1->FileName.c_str( ), "rt" );
    if ( !tf ){
      ShowMessage("Error: Could not open COMPRESION Table file." );
      return;
    }

    //
    while( fgets( buf, 256, tf ) ){
      // DTE??
      RemoveLF_CR( buf );
      //
      if ( buf[2] == '=' ){
        buf[2] = 0;
        strcpy( dte[ strtol(buf, NULL, 16) ], &buf[3] );
      } else
      // Dictionary??
      if ( buf[4] == '=' ){
        buf[4] = 0;
        strcpy( cmp[ strtol(buf, NULL, 16) & 0x1FF ], &buf[5] );
      }
    }// WEND
  }
}








